package com.hy.${packageCode}.shared.autoconfigure.distribute;

import com.hy.${packageCode}.shared.distribute.cache.DistCache;
import com.hy.${packageCode}.shared.distribute.lock.DistLock;
import com.hy.${packageCode}.shared.distribute.lock.DistReadWriteLock;
import com.hy.${packageCode}.shared.distribute.map.DistMap;
import com.hy.${packageCode}.shared.distribute.rate.DistRateLimiter;
import com.hy.${packageCode}.shared.distribute.DistObjectFactory;
import com.hy.${packageCode}.shared.distribute.DistributionObjectFactory;
import com.hy.${packageCode}.shared.distribute.cache.DistCache;
import com.hy.${packageCode}.shared.distribute.counter.DistCounter;
import com.hy.${packageCode}.shared.distribute.election.DistLeaderElection;
import com.hy.${packageCode}.shared.distribute.lock.DistLock;
import com.hy.${packageCode}.shared.distribute.lock.DistReadWriteLock;
import com.hy.${packageCode}.shared.distribute.map.DistMap;
import com.hy.${packageCode}.shared.distribute.rate.DistRateLimiter;
import com.hy.${packageCode}.shared.distribute.standalone.StandaloneObjectFactory;
import com.hy.${packageCode}.shared.distribute.cache.DistCache;
import com.hy.${packageCode}.shared.distribute.lock.DistLock;
import com.hy.${packageCode}.shared.distribute.lock.DistReadWriteLock;
import com.hy.${packageCode}.shared.distribute.map.DistMap;
import com.hy.${packageCode}.shared.distribute.rate.DistRateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Slf4j
@Configuration
@ConditionalOnClass({RedissonAutoConfigurationCustomizer.class})
@AutoConfigureAfter({RedissonAutoConfiguration.class, RedisAutoConfiguration.class})
public class DistributeAutoConfiguration {
    private static final String REDISSON_CLASS_NAME = "org.redisson.api.RedissonClient";

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(type = {REDISSON_CLASS_NAME})
    public DistObjectFactory distObjectFactory(@Autowired RedissonClient redissonClient) {
        log.info("Using distribution object factory with redisson support ");
        return new DistributionObjectFactory(redissonClient);
    }

    @Bean
    @ConditionalOnMissingBean(type = {REDISSON_CLASS_NAME}, value = {DistObjectFactory.class})
    public DistObjectFactory aloneObjectFactory() {
        log.info("Using standalone object factory with redisson support");
        return new StandaloneObjectFactory();
    }

    @Bean("newDistMap")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public <K, V> DistMap<K, V> newDistMap(@Autowired DistObjectFactory objectFactory, String name) {
        return objectFactory.getMap(name);
    }

    @Bean("newDistCache")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public <K, V> DistCache<K, V> newDistCache(@Autowired DistObjectFactory objectFactory, String name) {
        return objectFactory.getCache(name);
    }

    @Bean("newDistCounter")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public DistCounter newDistCounter(@Autowired DistObjectFactory objectFactory, String name) {
        return objectFactory.getCounter(name);
    }

    @Bean("newDistLock")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public DistLock newDistLock(@Autowired DistObjectFactory objectFactory, String name) {
        return objectFactory.getLock(name);
    }

    @Bean("newDistReadWriteLock")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public DistReadWriteLock newDistReadWriteLock(@Autowired DistObjectFactory objectFactory, String name) {
        return objectFactory.getReadWriteLock(name);
    }

    @Bean("newLeaderElection")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public DistLeaderElection newLeaderElection(@Autowired DistObjectFactory objectFactory, String name) {
        return objectFactory.getLeaderElection(name);
    }

    @Bean("newRateLimiter")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public DistRateLimiter newRateLimiter(@Autowired DistObjectFactory objectFactory, String name) {
        return objectFactory.getRateLimiter(name);
    }

}
